from .file import replace_ext, abspath
from .base import Object, Set
from .constants import (unpack,
                        WdExportFormat,
                        WdExportOptimizeFor,
                        WdExportRange,
                        WdExportItem,
                        WdExportCreateBookmarks,
                        WdOpenFormat,
                        WdDocumentDirection,
                        WdOriginalFormat,
                        MsoEncoding)
from .paragraph import Paragraphs
from .style import Styles
from .word import Application
from .field import Fields
from ctypes import c_long
from pywintypes import com_error

class Document(Object):
    # properties
    @property
    def ActiveTheme(self):
        return self.Instance.ActiveTheme

    @property
    def ActiveThemeDisplayName(self):
        return self.Instance.ActiveThemeDisplayName

    @property
    def ActiveWindow(self):
        return self.Instance.ActiveWindow

    @property
    def ActiveWritingStyle(self):
        return self.Instance.ActiveWritingStyle

    @property
    def Application(self) -> Application:
        return Application(self.Instance.Application)

    @property
    def AttachedTemplate(self):
        return self.Instance.AttachedTemplate

    @property
    def AutoFormatOverride(self):
        return self.Instance.AutoFormatOverride

    @property
    def AutoHyphenation(self):
        return self.Instance.AutoHyphenation

    @property
    def AutoSaveOn(self):
        return self.Instance.AutoSaveOn

    @property
    def Background(self):
        return self.Instance.Background

    @property
    def Bibliography(self):
        return self.Instance.Bibliography

    @property
    def Bookmarks(self):
        return self.Instance.Bookmarks

    @property
    def Broadcast(self):
        return self.Instance.Broadcast

    @property
    def BuiltInDocumentProperties(self):
        return self.Instance.BuiltInDocumentProperties

    @property
    def Characters(self):
        return self.Instance.Characters

    @property
    def ChartDataPointTrack(self):
        return self.Instance.ChartDataPointTrack

    @property
    def ClickAndTypeParagraphStyle(self):
        return self.Instance.ClickAndTypeParagraphStyle

    @property
    def CoAuthoring(self):
        return self.Instance.CoAuthoring

    @property
    def CodeName(self):
        return self.Instance.CodeName

    @property
    def CommandBars(self):
        return self.Instance.CommandBars

    @property
    def Comments(self):
        return self.Instance.Comments

    @property
    def Compatibility(self):
        return self.Instance.Compatibility

    @property
    def CompatibilityMode(self):
        return self.Instance.CompatibilityMode

    @property
    def ConsecutiveHyphensLimit(self):
        return self.Instance.ConsecutiveHyphensLimit

    @property
    def Container(self):
        return self.Instance.Container

    @property
    def Content(self):
        return self.Instance.Content

    @property
    def ContentControls(self):
        return self.Instance.ContentControls

    @property
    def ContentTypeProperties(self):
        return self.Instance.ContentTypeProperties

    @property
    def Creator(self):
        return self.Instance.Creator

    @property
    def CurrentRsid(self):
        return self.Instance.CurrentRsid

    @property
    def CustomDocumentProperties(self):
        return self.Instance.CustomDocumentProperties

    @property
    def CustomXMLParts(self):
        return self.Instance.CustomXMLParts

    @property
    def DefaultTableStyle(self):
        return self.Instance.DefaultTableStyle

    @property
    def DefaultTabStop(self):
        return self.Instance.DefaultTabStop

    @property
    def DefaultTargetFrame(self):
        return self.Instance.DefaultTargetFrame

    @property
    def DisableFeatures(self):
        return self.Instance.DisableFeatures

    @property
    def DisableFeaturesIntroducedAfter(self):
        return self.Instance.DisableFeaturesIntroducedAfter

    @property
    def DocumentInspectors(self):
        return self.Instance.DocumentInspectors

    @property
    def DocumentLibraryVersions(self):
        return self.Instance.DocumentLibraryVersions

    @property
    def DocumentTheme(self):
        return self.Instance.DocumentTheme

    @property
    def DoNotEmbedSystemFonts(self):
        return self.Instance.DoNotEmbedSystemFonts

    @property
    def Email(self):
        return self.Instance.Email

    @property
    def EmbedLinguisticData(self):
        return self.Instance.EmbedLinguisticData

    @property
    def EmbedTrueTypeFonts(self):
        return self.Instance.EmbedTrueTypeFonts

    @property
    def EncryptionProvider(self):
        return self.Instance.EncryptionProvider

    @property
    def Endnotes(self):
        return self.Instance.Endnotes

    @property
    def EnforceStyle(self):
        return self.Instance.EnforceStyle

    @property
    def Envelope(self):
        return self.Instance.Envelope

    @property
    def FarEastLineBreakLanguage(self):
        return self.Instance.FarEastLineBreakLanguage

    @property
    def FarEastLineBreakLevel(self):
        return self.Instance.FarEastLineBreakLevel

    @property
    def Fields(self) -> Fields:
        return Fields(self.Instance.Fields)

    @property
    def Final(self):
        return self.Instance.Final

    @property
    def Footnotes(self):
        return self.Instance.Footnotes

    @property
    def FormattingShowClear(self):
        return self.Instance.FormattingShowClear

    @property
    def FormattingShowFilter(self):
        return self.Instance.FormattingShowFilter

    @property
    def FormattingShowFont(self):
        return self.Instance.FormattingShowFont

    @property
    def FormattingShowNextLevel(self):
        return self.Instance.FormattingShowNextLevel

    @property
    def FormattingShowNumbering(self):
        return self.Instance.FormattingShowNumbering

    @property
    def FormattingShowParagraph(self):
        return self.Instance.FormattingShowParagraph

    @property
    def FormattingShowUserStyleName(self):
        return self.Instance.FormattingShowUserStyleName

    @property
    def FormFields(self):
        return self.Instance.FormFields

    @property
    def FormsDesign(self):
        return self.Instance.FormsDesign

    @property
    def Frames(self):
        return self.Instance.Frames

    @property
    def Frameset(self):
        return self.Instance.Frameset

    @property
    def FullName(self):
        return self.Instance.FullName

    @property
    def GrammarChecked(self):
        return self.Instance.GrammarChecked

    @property
    def GrammaticalErrors(self):
        return self.Instance.GrammaticalErrors

    @property
    def GridDistanceHorizontal(self):
        return self.Instance.GridDistanceHorizontal

    @property
    def GridDistanceVertical(self):
        return self.Instance.GridDistanceVertical

    @property
    def GridOriginFromMargin(self):
        return self.Instance.GridOriginFromMargin

    @property
    def GridOriginHorizontal(self):
        return self.Instance.GridOriginHorizontal

    @property
    def GridOriginVertical(self):
        return self.Instance.GridOriginVertical

    @property
    def GridSpaceBetweenHorizontalLines(self):
        return self.Instance.GridSpaceBetweenHorizontalLines

    @property
    def GridSpaceBetweenVerticalLines(self):
        return self.Instance.GridSpaceBetweenVerticalLines

    @property
    def HasPassword(self):
        return self.Instance.HasPassword

    @property
    def HasVBProject(self):
        return self.Instance.HasVBProject

    @property
    def HTMLDivisions(self):
        return self.Instance.HTMLDivisions

    @property
    def Hyperlinks(self):
        return self.Instance.Hyperlinks

    @property
    def HyphenateCaps(self):
        return self.Instance.HyphenateCaps

    @property
    def HyphenationZone(self):
        return self.Instance.HyphenationZone

    @property
    def Indexes(self):
        return self.Instance.Indexes

    @property
    def InlineShapes(self):
        return self.Instance.InlineShapes

    @property
    def IsInAutosave(self):
        return self.Instance.IsInAutosave

    @property
    def IsMasterDocument(self):
        return self.Instance.IsMasterDocument

    @property
    def IsSubdocument(self):
        return self.Instance.IsSubdocument

    @property
    def JustificationMode(self):
        return self.Instance.JustificationMode

    @property
    def KerningByAlgorithm(self):
        return self.Instance.KerningByAlgorithm

    @property
    def Kind(self):
        return self.Instance.Kind

    @property
    def LanguageDetected(self):
        return self.Instance.LanguageDetected

    @property
    def ListParagraphs(self):
        return self.Instance.ListParagraphs

    @property
    def Lists(self):
        return self.Instance.Lists

    @property
    def ListTemplates(self):
        return self.Instance.ListTemplates

    @property
    def LockQuickStyleSet(self):
        return self.Instance.LockQuickStyleSet

    @property
    def LockTheme(self):
        return self.Instance.LockTheme

    @property
    def MailEnvelope(self):
        return self.Instance.MailEnvelope

    @property
    def MailMerge(self):
        return self.Instance.MailMerge

    @property
    def Name(self) -> str:
        return self.Instance.Name

    @property
    def NoLineBreakAfter(self):
        return self.Instance.NoLineBreakAfter

    @property
    def NoLineBreakBefore(self):
        return self.Instance.NoLineBreakBefore

    @property
    def OMathBreakBin(self):
        return self.Instance.OMathBreakBin

    @property
    def OMathBreakSub(self):
        return self.Instance.OMathBreakSub

    @property
    def OMathFontName(self):
        return self.Instance.OMathFontName

    @property
    def OMathIntSubSupLim(self):
        return self.Instance.OMathIntSubSupLim

    @property
    def OMathJc(self):
        return self.Instance.OMathJc

    @property
    def OMathLeftMargin(self):
        return self.Instance.OMathLeftMargin

    @property
    def OMathNarySupSubLim(self):
        return self.Instance.OMathNarySupSubLim

    @property
    def OMathRightMargin(self):
        return self.Instance.OMathRightMargin

    @property
    def OMaths(self):
        return self.Instance.OMaths

    @property
    def OMathSmallFrac(self):
        return self.Instance.OMathSmallFrac

    @property
    def OMathWrap(self):
        return self.Instance.OMathWrap

    @property
    def OpenEncoding(self):
        return self.Instance.OpenEncoding

    @property
    def OptimizeForWord97(self):
        return self.Instance.OptimizeForWord97

    @property
    def OriginalDocumentTitle(self):
        return self.Instance.OriginalDocumentTitle

    @property
    def PageSetup(self):
        return self.Instance.PageSetup

    @property
    def Paragraphs(self) -> Paragraphs:
        return Paragraphs(self.Instance.Paragraphs)

    @property
    def Parent(self):
        return self.Instance.Parent

    @property
    def Password(self):
        return self.Instance.Password

    @property
    def PasswordEncryptionAlgorithm(self):
        return self.Instance.PasswordEncryptionAlgorithm

    @property
    def PasswordEncryptionFileProperties(self):
        return self.Instance.PasswordEncryptionFileProperties

    @property
    def PasswordEncryptionKeyLength(self):
        return self.Instance.PasswordEncryptionKeyLength

    @property
    def PasswordEncryptionProvider(self):
        return self.Instance.PasswordEncryptionProvider

    @property
    def Path(self):
        return self.Instance.Path

    @property
    def Permission(self):
        return self.Instance.Permission

    @property
    def PrintFormsData(self):
        return self.Instance.PrintFormsData

    @property
    def PrintPostScriptOverText(self):
        return self.Instance.PrintPostScriptOverText

    @property
    def PrintRevisions(self):
        return self.Instance.PrintRevisions

    @property
    def ProtectionType(self):
        return self.Instance.ProtectionType

    @property
    def ReadabilityStatistics(self):
        return self.Instance.ReadabilityStatistics

    @property
    def ReadingLayoutSizeX(self):
        return self.Instance.ReadingLayoutSizeX

    @property
    def ReadingLayoutSizeY(self):
        return self.Instance.ReadingLayoutSizeY

    @property
    def ReadingModeLayoutFrozen(self):
        return self.Instance.ReadingModeLayoutFrozen

    @property
    def ReadOnly(self):
        return self.Instance.ReadOnly

    @property
    def ReadOnlyRecommended(self):
        return self.Instance.ReadOnlyRecommended

    @property
    def RemoveDateAndTime(self):
        return self.Instance.RemoveDateAndTime

    @property
    def RemovePersonalInformation(self):
        return self.Instance.RemovePersonalInformation

    @property
    def Research(self):
        return self.Instance.Research

    @property
    def RevisedDocumentTitle(self):
        return self.Instance.RevisedDocumentTitle

    @property
    def Revisions(self):
        return self.Instance.Revisions

    @property
    def Saved(self):
        return self.Instance.Saved

    @property
    def SaveEncoding(self):
        return self.Instance.SaveEncoding

    @property
    def SaveFormat(self):
        return self.Instance.SaveFormat

    @property
    def SaveFormsData(self):
        return self.Instance.SaveFormsData

    @property
    def SaveSubsetFonts(self):
        return self.Instance.SaveSubsetFonts

    @property
    def Scripts(self):
        return self.Instance.Scripts

    @property
    def Sections(self):
        return self.Instance.Sections

    @property
    def 敏感度标签(self):
        return self.Instance.敏感度标签

    @property
    def Sentences(self):
        return self.Instance.Sentences

    @property
    def ServerPolicy(self):
        return self.Instance.ServerPolicy

    @property
    def Shapes(self):
        return self.Instance.Shapes

    @property
    def ShowGrammaticalErrors(self):
        return self.Instance.ShowGrammaticalErrors

    @property
    def ShowSpellingErrors(self):
        return self.Instance.ShowSpellingErrors

    @property
    def Signatures(self):
        return self.Instance.Signatures

    @property
    def SmartDocument(self):
        return self.Instance.SmartDocument

    @property
    def SnapToGrid(self):
        return self.Instance.SnapToGrid

    @property
    def SnapToShapes(self):
        return self.Instance.SnapToShapes

    @property
    def SpellingChecked(self):
        return self.Instance.SpellingChecked

    @property
    def SpellingErrors(self):
        return self.Instance.SpellingErrors

    @property
    def StoryRanges(self):
        return self.Instance.StoryRanges

    @property
    def Styles(self) -> Styles:
        return Styles(self.Instance.Styles)

    @property
    def StyleSheets(self):
        return self.Instance.StyleSheets

    @property
    def StyleSortMethod(self):
        return self.Instance.StyleSortMethod

    @property
    def Subdocuments(self):
        return self.Instance.Subdocuments

    @property
    def Sync(self):
        return self.Instance.Sync

    @property
    def Tables(self):
        return self.Instance.Tables

    @property
    def TablesOfAuthorities(self):
        return self.Instance.TablesOfAuthorities

    @property
    def TablesOfAuthoritiesCategories(self):
        return self.Instance.TablesOfAuthoritiesCategories

    @property
    def TablesOfContents(self):
        return self.Instance.TablesOfContents

    @property
    def TablesOfFigures(self):
        return self.Instance.TablesOfFigures

    @property
    def TextEncoding(self):
        return self.Instance.TextEncoding

    @property
    def TextLineEnding(self):
        return self.Instance.TextLineEnding

    @property
    def TrackFormatting(self):
        return self.Instance.TrackFormatting

    @property
    def TrackMoves(self):
        return self.Instance.TrackMoves

    @property
    def TrackRevisions(self):
        return self.Instance.TrackRevisions

    @property
    def Type(self):
        return self.Instance.Type

    @property
    def UpdateStylesOnOpen(self):
        return self.Instance.UpdateStylesOnOpen

    @property
    def UseMathDefaults(self):
        return self.Instance.UseMathDefaults

    @property
    def UserControl(self):
        return self.Instance.UserControl

    @property
    def Variables(self):
        return self.Instance.Variables

    @property
    def VBASigned(self):
        return self.Instance.VBASigned

    @property
    def VBProject(self):
        return self.Instance.VBProject

    @property
    def WebOptions(self):
        return self.Instance.WebOptions

    @property
    def Windows(self):
        return self.Instance.Windows

    @property
    def WordOpenXML(self):
        return self.Instance.WordOpenXML

    @property
    def Words(self):
        return self.Instance.Words

    @property
    def WritePassword(self):
        return self.Instance.WritePassword

    @property
    def WriteReserved(self):
        return self.Instance.WriteReserved

    @property
    def XMLSaveThroughXSLT(self):
        return self.Instance.XMLSaveThroughXSLT

    @property
    def XMLSchemaReferences(self):
        return self.Instance.XMLSchemaReferences

    @property
    def XMLShowAdvancedErrors(self):
        return self.Instance.XMLShowAdvancedErrors

    @property
    def XMLUseXSLTWhenSaving(self):
        return self.Instance.XMLUseXSLTWhenSaving

    # methods
    def Save(self,
             NoPrompt:bool = True,
             OriginalFormat: WdOriginalFormat = WdOriginalFormat.wdOriginalDocumentFormat
             ):
        """ 保存指定的文档。

            语法
            表达式.保存

            expression 是必需的。 一个代表 Document 对象的变量。

            参数：

            NoPrompt (可选)

            如果 true 为 ，则 Word 自动保存所有文档。 如果为 ，则 Word 将提示用户保存自上次保存以来更改 false 的每个文档。

            OriginalFormat (可选)

            指定文档的保存的方式。 可以是 WdOriginalFormat 常量之一。
        """
        self.Instance.Save(NoPrompt, OriginalFormat)

    def SaveAs2(self, **kwargs):
        """ 使用新的名称或格式保存指定的文档。 此方法的一些参数与 “另存为” 对话框（“文件” 选项卡）中的选项相对应。

            语法
            expression。 SaveAs2( _FileName_ , _FileFormat_ , _LockComments_ , _Password_ , _AddToRecentFiles_ , _WritePassword_ , _ReadOnlyRecommended_ , _EmbedTrueTypeFonts_ , _SaveNativePictureFormat_ , _SaveFormsData_ , _SaveAsAOCELetter_ , _Encoding_ , _InsertLineBreaks_ , _AllowSubstitutions_ , _LineEnding_ , _AddBiDiMarks_ , _CompatibilityMode_ )

            表达式 一个返回 Document 对象的 表达式。

            参数
            参数
            名称	必需/可选	数据类型	说明
            FileName	可选	Variant	文档的名称。 默认值为当前文件夹和文件名。 如果从未保存过文档，将使用默认名称（例如，Doc1.doc）。 如果已经存在具有指定文件名的文档，则覆盖该文档，并且在覆盖前不提示用户。
            FileFormat	可选	Variant	文档的保存格式。 可以是任何 WdSaveFormat 常量。 若要以另一种格式保存文档，请为 FileConverter 对象的 SaveFormat 属性指定适当的值。
            LockComments	可选	Variant	如果为 True，则锁定文档注释。 默认值为 False。
            Password	可选	Variant	用于打开文档的密码字符串。 （请参阅下面的“备注”。）
            AddToRecentFiles	可选	Variant	如果为 True，则将文档添加到“文件”菜单上最近使用的文件列表中。 默认值为 True。
            WritePassword	可选	Variant	用于保存文档更改的密码字符串。 （请参阅下面的“备注”。）
            ReadOnlyRecommended	可选	Variant	如果为 True，则每次打开文档时，Microsoft Word 都将建议采用只读方式。 默认值为 False。
            EmbedTrueTypeFonts	可选	Variant	如果为 True，则 TrueType 字体随文档一起保存。 如果省略，则 EmbedTrueTypeFonts 参数将假定为 EmbedTrueTypeFonts 属性的值。
            SaveNativePictureFormat	可选	Variant	如果为 True，则对于从其他系统平台（如 Macintosh）导入的图形，只保存其 Microsoft Windows 版本。
            SaveFormsData	可选	Variant	如果为 True，则将用户在窗体中输入的数据保存为记录。
            SaveAsAOCELetter	可选	Variant	如果文档包含附加的邮件，当为 True 时，将文档存为 AOCE 信函（同时保存邮件）。
            Encoding	可选	Variant	用于另存为编码文本文件的文档的代码页或字符集。 默认值是系统代码页。 不能将所有 MsoEncoding 常量用于此参数。
            InsertLineBreaks	可选	Variant	在将文档另存为文本文件时，如果为 True，则在每一行文本后插入换行符。
            AllowSubstitutions	可选	Variant	将文档另存为文本文件时，如果为 True，则 Word 可以将一些符号替换为相似的文本。 例如，将版权符号显示为 (c)。 默认值为 False。
            LineEnding	可选	Variant	Word 在另存为文本文件的文档中标记换行符和分段符的方式。 可以是以下 WdLineEndingType 常量之一：wdCRLF（默认值）或 wdCROnly。
            AddBiDiMarks	可选	Variant	如果为 True，则为输出文件添加控制符，以保留原始文档中文本的双向版式。
            CompatibilityMode	可选	Variant	打开文档时，Word 使用的兼容性模式。 WdCompatibilityMode 常量。
            表 2
            重要说明
            默认情况下，如果没有为此参数指定任何值，则 Word 输入值 0，这会指定应保留文档的当前兼容性模式。
        """
        FileName = kwargs.pop('FileName')
        print(f'Saveas2 : {FileName}')
        FileName = abspath(FileName)
        print(f'Saveas2 abspath: {FileName}')
        self.Instance.SaveAs2(FileName=FileName, **kwargs)

    def ExportAsFixedFormat(self,
                            OutputFileName=None,
                            ExportFormat:WdExportFormat=WdExportFormat.wdExportFormatPDF,
                            OpenAfterExport=True,
                            OptimizeFor:WdExportOptimizeFor=WdExportOptimizeFor.wdExportOptimizeForPrint,
                            Range:WdExportRange=WdExportRange.wdExportAllDocument,
                            From:c_long=1,
                            To:c_long=1,
                            Item:WdExportItem=WdExportItem.wdExportDocumentContent,
                            IncludeDocProps=True,
                            KeepIRM=True,
                            CreateBookmarks:WdExportCreateBookmarks=WdExportCreateBookmarks.wdExportCreateNoBookmarks,
                            DocStructureTags=True,
                            BitmapMissingFonts=True,
                            UseISO19005_1=False,
                            FixedFormatExtClassPtr=None
                            ):
        if OutputFileName is None:
            OutputFileName = replace_ext(self.FullName)
        kwargs = {}
        kwargs['ExportFormat'] = unpack(ExportFormat)
        kwargs['OpenAfterExport'] = unpack(OpenAfterExport)
        kwargs['OptimizeFor'] = unpack(OptimizeFor)
        kwargs['Range'] = unpack(Range)
        kwargs['From'] = unpack(From)
        kwargs['To'] = unpack(To)
        kwargs['Item'] = unpack(Item)
        kwargs['IncludeDocProps'] = unpack(IncludeDocProps)
        kwargs['KeepIRM'] = unpack(KeepIRM)
        kwargs['CreateBookmarks'] = unpack(CreateBookmarks)
        kwargs['DocStructureTags'] = unpack(DocStructureTags)
        kwargs['BitmapMissingFonts'] = unpack(BitmapMissingFonts)
        kwargs['UseISO19005_1'] = unpack(UseISO19005_1)
        if FixedFormatExtClassPtr is not None:
            kwargs['FixedFormatExtClassPtr'] = unpack(FixedFormatExtClassPtr)
        try:
            doc = self.Instance.ExportAsFixedFormat(OutputFileName, **kwargs)
            return Document(doc)
        except com_error as e:
            print(f'Export Error: {e}:{type(e)}')
            raise ValueError


class Documents(Set):
    def __init__(self, instance):
        super().__init__(instance, elementType=Document)

    def Add(self, Template=None, NewTemplate=False, DocumentType=None, Visible=True):
        return Document(self.Instance.Add())

    def Open(self, FileName,
             ConfirmConversions=True,
             ReadOnly=True,
             AddToRecentFiles=True,
             PasswordDocument=None,
             PasswordTemplate=None,
             Revert=False,
             WritePasswordDocument=None,
             WritePasswordTemplate=None,
             Format:WdOpenFormat=WdOpenFormat.wdOpenFormatAuto,
             Encoding:MsoEncoding=MsoEncoding.msoEncodingSimplifiedChineseAutoDetect,
             Visible=True,
             OpenConflictDocument=True,
             OpenAndRepair=True,
             DocumentDirection:WdDocumentDirection=WdDocumentDirection.wdLeftToRight,
             NoEncodingDialog=False
             ):
        from os.path import split, splitext, sep, exists
        directory, fileName = split(FileName)
        name, ext = splitext(fileName)
        FileName = directory + sep + name + ext
        assert(ext == '.docx' or ext == '.doc')
        assert(self.Instance is not None)
        kwargs = {
            'ConfirmConversions': True,
            'ReadOnly': True,
            'AddToRecentFiles': True,
            'Revert': False,
        }
        doc = self.Instance.Open(FileName, **kwargs)
        return Document(doc)

    def saveobj(self):
        return {
                'Paragraphs': self.Paragraphs.saveobj(),
                'Styles': self.Styles.saveobj()
                }

